<?php

class base_kvstore {

    private static $__instance = array();

    private static $__persistent = true;

    private $__controller = null;

    private $__prefix = null;

    public static $__fetch_count = 0;

    public static $__store_count = 0;

    function __construct($prefix) {
        if (defined('FORCE_KVSTORE_STORAGE') && constant('FORCE_KVSTORE_STORAGE')) {
            $this->set_controller(kernel::single(FORCE_KVSTORE_STORAGE, $prefix));
        } else {
            if (defined('KVSTORE_STORAGE') && constant('KVSTORE_STORAGE')) {
                $this->set_controller(kernel::single(KVSTORE_STORAGE, $prefix));
            } else {
                $this->set_controller(kernel::single('base_kvstore_filesystem', $prefix));
            }
        }
        $this->set_prefix($prefix);
    }
 // End Function
    static function config_persistent($flag) {
        self::$__persistent = ($flag) ? true : false;
    }
 // End Function
    static public function kvprefix() {
        // return (defined('KV_PREFIX')) ? KV_PREFIX : 'default';
        return (defined('KV_PREFIX')) ? KV_PREFIX : 'defalut'; // define里的KV_PREFIX从第一版就写错了，所以这里只好将错就错。。
    }
 // End Function
    static public function instance($prefix) {
        if (! isset(self::$__instance[$prefix])) {
            self::$__instance[$prefix] = new base_kvstore($prefix);
        }
        return self::$__instance[$prefix];
    }
 // End Function
    public function set_prefix($prefix) {
        $this->__prefix = $prefix;
    }
 // End Function
    public function get_prefix() {
        return $this->__prefix;
    }
 // End Function
    public function set_controller($controller) {
        if ($controller instanceof base_interface_kvstore_base) {
            $this->__controller = $controller;
        } else {
            throw new Exception('this instance must implements base_interface_kvstore_base');
        }
    }
 // End Function
    public function get_controller() {
        return $this->__controller;
    }
 // End Function
    public function increment($key, $offset = 1) {
        if ($this->get_controller() instanceof base_interface_kvstore_extension) {
            return $this->get_controller()->increment($key, $offset);
        } else {
            throw new Exception('this instance can\'t support increment');
        }
    }
 // End Function
    public function decrement($key, $offset = 1) {
        if ($this->get_controller() instanceof base_interface_kvstore_extension) {
            return $this->get_controller()->decrement($key, $offset);
        } else {
            throw new Exception('this instance can\'t support decrement');
        }
    }
 // End Function
    public function fetch($key, &$value, $timeout_version = null) {
        self::$__fetch_count++;
        logger::debug('kvstore:' . self::$__fetch_count . '.' . ' instance:' . $this->get_prefix() . ' fetch key:' . $key);
        if ($this->get_controller()->fetch($key, $value, $timeout_version)) {
            return true;
        } else {
            return false;
        }
    }
 // End Function
    public function store($key, $value, $ttl = 0) {
        self::$__store_count++;
        if (! (defined('WITHOUT_KVSTORE_PERSISTENT') && constant('WITHOUT_KVSTORE_PERSISTENT')) && self::$__persistent && get_class($this->get_controller()) != 'base_kvstore_mysql' && kernel::is_online()) {
            $this->persistent($key, $value, $ttl);
        }
        logger::debug('kvstore:' . self::$__fetch_count . '.' . ' instance:' . $this->get_prefix() . ' store key:' . $key);
        return $this->get_controller()->store($key, $value, $ttl);
    }
 // End Function
    public function delete($key, $ttl = 1) {
        if ($this->fetch($key, $value)) {
            return $this->store($key, $value, ($ttl > 0) ? $ttl : 1); // todo: 不实际删除，由cron统一处理delete
        }
        return true;
    }
 // End Function
    public function persistent($key, $value, $ttl = 0) {
        kernel::single('base_kvstore_mysql', $this->get_prefix())->store($key, $value, $ttl); // todo: 持久化
    }
 // End Function
    public function recovery($record) {
        return $this->get_controller()->recovery($record);
    }
 // End Function
    static public function delete_expire_data() {
        $time = time();
        $count = kernel::database()->count('SELECT count(*) FROM sdb_base_kvstore WHERE ttl>0 AND (dateline+ttl)<' . $time);
        $pagesize = 100;
        $page = ceil($count / 100);
        for ($i = 0; $i < $page; $i++) {
            $rows = kernel::database()->selectlimit('SELECT `prefix`, `key` FROM sdb_base_kvstore WHERE ttl>0 AND (dateline+ttl)<' . $time, $pagesize, $i * $pagesize);
            foreach ($rows as $row) {
                $single = base_kvstore::instance($row['prefix']);
                if (get_class($single->get_controller()) != 'base_kvstore_mysql') {
                    $single->get_controller()->delete($row['key']);
                }
            }
        }
        kernel::database()->exec('DELETE FROM sdb_base_kvstore WHERE ttl>0 AND (dateline+ttl)<' . $time, true);
    } // End Function
}//End Class
